package core;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import java.util.logging.Logger;

import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;

import domain.User;

/**
 * @author DGW-PC
 * @data 2018年8月28日下午8:47:37 <a href="https://www.cnblogs.com/dgwblog/">我的博客</a>
 */
@Controller
@SessionAttributes(value= {"user"})//加入httpSession
public class SpringMvcCore {

	private static Logger logger = Logger.getLogger(SpringMvcCore.class.getName());

	private final String SUCCESS = "success";
	
	/**
	 * 1. 有 @ModelAttribute 标记的方法, 会在每个目标方法执行之前被 SpringMVC 调用! 
	 * 2. @ModelAttribute 注解也可以来修饰目标方法 POJO 类型的入参, 其 value 属性值有如下的作用:
	 * 1). SpringMVC 会使用 value 属性值在 implicitModel 中查找对应的对象, 若存在则会直接传入到目标方法的入参中.
	 * 2). SpringMVC 会一 value 为 key, POJO 类型的对象为 value, 存入到 request 中. 
	 */
	@ModelAttribute
	public void getUser(@RequestParam(value="id",required=false) Integer id,Model model) {
		System.out.println("执行查询User对象");
		if(id!=null) {
			//模拟创建User对象 数据库操作
			User user = new User(1, "admin", "admin123", "123@qq.com");
			model.addAttribute("user", user);
		}
	}
	
	/**
	 * * 运行流程:
	 * 1. 执行 @ModelAttribute 注解修饰的方法: 从数据库中取出对象, 把对象放入到了 Map 中. 键为: user
	 * 2. SpringMVC 从 Map 中取出 User 对象, 并把表单的请求参数赋给该 User 对象的对应属性.
	 * 3. SpringMVC 把上述对象传入目标方法的参数. 
	 * 
	 * 注意: 在 @ModelAttribute 修饰的方法中, 放入到 Map 时的键需要和目标方法入参类型的第一个字母小写的字符串一致!
	 * @param user
	 * @return String
	 */
	@RequestMapping("/testModelAttribute")
	public String testModelAttribute(User user) {
		System.out.println("修改操作"+user);	
		return SUCCESS;
	}
	
	/**
	 * @SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外(实际上使用的是 value 属性值),
	 * 还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中(实际上使用的是 types 属性值)
	 * 
	 * 注意: 该注解只能放在类的上面. 而不能修饰放方法. 
	 */
	@RequestMapping(value = "/testSessionAttribute")
	public String testSessionAttribute(ModelMap modelMap) {
		//model.put("user", Arrays.asList("tom","gray","shek"));
		modelMap.addAttribute("user", Arrays.asList("tom","gray","shek"));
		return SUCCESS;
	}
	
	
	/**
	 * 使用modelmap
	 * @param model
	 * @return String
	 */
	@RequestMapping(value = "/testModelAndMapToModelMap")
	public String testModelAndMapToModelMap(ModelMap modelMap) {
		//model.put("user", Arrays.asList("tom","gray","shek"));
		modelMap.addAttribute("user", Arrays.asList("tom","gray","shek"));
		return SUCCESS;
	}
	
	/**
	 *使用model 
	 * @param model
	 * @return String
	 */
	@RequestMapping(value = "/testModelAndMapToModel")
	public String testModelAndMapToModel(Model model) {
		//model.put("user", Arrays.asList("tom","gray","shek"));
		model.addAttribute("user", Arrays.asList("tom","gray","shek"));
		return SUCCESS;
	}
	
	/**
	 * ModelAndView是Model Map ModelMap 渲染到视图的最后对象 
	 * @param map
	 * @return String
	 */
	@RequestMapping(value = "/testModelAndMapToMap")
	public String testModelAndMapToMap(Map<String, Object> map) {
		map.put("user", Arrays.asList("tom","gray","shek"));
		return SUCCESS;
	}
	
	/**
	 * 根据视图名字来解析数据. 并且将数据传回到
	 * 当前页面的请求域对象中
	 */
	@RequestMapping(value = "/testModelAndVew")
	public ModelAndView testModelAndVew() {
		ModelAndView view = new ModelAndView(SUCCESS);
		view.addObject("time", new Date().toString());
		return view;
	}
	
	/**
	 * 一些servlet对象入参，springmvc 根据入参对象来自动加载对象
	 * @param response
	 * @throws IOException void
	 */
	@RequestMapping("/SevletApi")
	public void tSevletApi(HttpServletResponse response) throws IOException {
		PrintWriter writer = response.getWriter();
		writer.write("spring mvc");
		//return SUCCESS;
	}

	/**
	 * 请求参数获取pojo时 
	 * 可以使用级联属性
	 * 要保证实体类的属性名要与前端的属性名相对应
	 * @param user
	 * @return String
	 */
	@RequestMapping(value="/testPojoRegister",method=RequestMethod.POST)
	public String testPojoRegister(User user) {
		logger.info("注册信息为"+user);
		return SUCCESS;
	}
}
